Scroll to navigation

GETRLIMIT(2) Руководство программиста Linux GETRLIMIT(2)

ИМЯ

getrlimit, setrlimit, prlimit - считывает/устанавливает ограничения использования ресурсов

ОБЗОР

#include <sys/time.h>
#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);

int prlimit(pid_t pid, int resource, const struct rlimit *new_limit,
struct rlimit *old_limit);


Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

prlimit(): _GNU_SOURCE && _FILE_OFFSET_BITS == 64

ОПИСАНИЕ

Системные вызовы getrlimit() и setrlimit(), соответственно, получают и устанавливают ограничения использования ресурсов. Каждому ресурсу назначается мягкое и жёсткое ограничение, определяемое структурой rlimit:


struct rlimit {

rlim_t rlim_cur; /* мягкое ограничение */
rlim_t rlim_max; /* жёсткое ограничение (максимум для rlim_cur) */ };

Мягким ограничением является значение, принудительно устанавливаемое ядром для соответствующего ресурса. Жёсткое ограничение работает как максимальное значение для мягкого ограничения: непривилегированные процессы могут определять только свои мягкие ограничения в диапазоне от 0 до жёсткого ограничения, то есть однозначно меньше жёсткого ограничения. Привилегированные процессы (в Linux: имеющие мандат CAP_SYS_RESOURCE) могут устанавливать произвольные значения в любых пределах.

Значение RLIM_INFINITY означает отсутствие ограничений для ресурса (в структуре, возвращаемой getrlimit() и в структуре, передаваемой в setrlimit()).

Значение resource должно быть одним из:

Максимальный размер виртуальной памяти (адресного пространства) процесса в байтах. Учитывается в вызовах brk(2), mmap(2) и mremap(2), которые завершатся с ошибкой ENOMEM, если будет превышено это ограничение. Также завершится с ошибкой автоматическое расширение стека (и будет сгенерирован сигнал SIGSEGV, по которому завершится процесс, если не было создано с помощью sigaltstack(2) альтернативного стека). Так как значение имеет тип long, на машинах с 32-битным long максимальное значение ограничения будет около 2 ГиБ, или этот ресурс не ограничивается.
Максимальный размер файла core. Если значение равно 0, то файлы core не создаются. Если значение больше нуля, то создаваемые дампы обрезаются до этого размера.
Время выполнения на ЦП в секундах. Когда процесс достигает своего мягкого ограничения, то ему отправляется сигнал SIGX CPU. Действием по умолчанию для этого сигнала является завершение процесса. Однако, этот сигнал может быть перехвачен, и обработчик может передать управление в основную программу. Если процесс продолжает потреблять процессорное время, то ему будет отправляться SIGXCPU раз в секунду до тех пор, пока не будет достигнуто жёсткое ограничение, и тогда процессу будет послан сигнал SIGKILL. (Последний пункт описывает поведение Linux. В разных реализациях действия над потребляющими процессорное время после прохождения мягкого ограничения процессами различаются. Переносимые приложения, где требуется перехват сигнала, должны выполнять корректное завершение процесса после первого получения SIGXCPU.)
Максимальный размер сегмента данных процесса (инициализированные данные, неинициализированные данные, куча). Это ограничение учитывается в вызовах brk(2) и sbrk(2), которые завершатся с ошибкой ENOMEM при достижении мягкого ограничения этого ресурса.
Максимальный размер файлов, создаваемых процессом. Попытки расширить файл сверх этого ограничения приведёт к доставке сигнала SIGXFSZ. По умолчанию по этому сигналу процесс завершается, но процесс может перехватить этот сигнал и в этом случае выполнявшийся системный вызов (например, write(2), truncate(2)) завершится с ошибкой EFBIG.
Ограничение на общее количество блокировок flock(2) и аренд fcntl(2), которое может установить процесс.
Максимальное количество байт памяти, которое может быть заблокировано в ОЗУ. В целях эффективности это ограничение округляется в меньшую сторону до ближайшего значения, кратного размеру системной страницы. Это ограничение учитывается в mlock(2) и mlockall(2) и в mmap(2) при операции MAP_LOCKED. Начиная с Linux 2.6.9, оно также учитывается в shmctl(2) при операции SHM_LOCK, где определяет максимальное количество байт всех общих сегментов памяти (см. shmget(2)), которые могут быть заблокированы вызывающим процессом с реальным идентификатором пользователя. Блокировки по операции SHM_LOCK у shmctl(2) учитываются отдельно от попроцессных блокировок памяти, устанавливаемых mlock(2), mlockall(2) и mmap(2) операцией MAP_LOCKED; процесс может заблокировать пространство до этого значения заданного ограничения байт в каждой из этих двух категорий. В ядрах Linux до версии 2.6.9 этим ограничением контролировалось количество памяти, которое можно было блокировать привилегированному процессу. Начиная с Linux 2.6.9 это ограничение снято и теперь это ограничение управляет количеством памяти, которое может блокировать непривилегированный процесс.
Ограничение на количество байт, которое может выделяться для очередей сообщений POSIX для вызывающего процесса с реальным идентификатором пользователя. Это ограничение учитывается в mq_open(3). Каждая очередь сообщений, которую создаёт пользователь, учитывается (пока не будет удалена) в формуле:

bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) +
attr.mq_maxmsg * attr.mq_msgsize
где attr — структура mq_attr, указанная в четвёртом аргументе mq_open(3).

Первое слагаемое в формуле, sizeof(struct msg_msg *) (4 байта в Linux/i386), нужно, чтобы пользователь не смог создать бесконечное количество сообщений нулевой длины (для таких сообщений, тем не менее, потребляется системная память для учёта использования системных ресурсов).

Определяет максимум, до которого может быть увеличено значение nice с помощью setpriority(2) или nice(2). Действительный максимум значения nice высчитывается по формуле: 20 - rlim_cur. (Так пришлось поступить из-за того, что отрицательные числа нельзя указывать в значениях ограничений ресурсов, так как они, обычно, имеют специальное предназначение. Например, RLIM_INFINITY, обычно равно -1.)
Определяет значение, на 1 больше максимального количества дескрипторов файлов, которое может открыть этот процесс. Попытки (open(2), pipe(2), dup(2) и т.п.) превысить это ограничение приведут к ошибке EMFILE. (Раньше это ограничение в BSD называлось RLIMIT_OFILE.)
Максимальное количество процессов (или, более точно для Linux, нитей), которое может создать вызывающий процесс с реальным идентификатором пользователя. При превышении этого ограничения fork(2) завершается с ошибкой EAGAIN.
Максимальное ограничение (в страницах) на число постоянных страниц процесса (числа виртуальных страниц, постоянно присутствующих в ОЗУ). Это ограничение учитывается только начиная с версии Linux 2.4.x, x < 30, и только в вызовах madvise(2) со значением MADV_WILLNEED.
Определяет максимум для приоритета реального времени, который можно установить для процесса с помощью sched_setscheduler(2) и sched_setparam(2).
Определяет ограничение (в микросекундах) на количество времени ЦП, которое процесс может быть запланирован выполняться в условиях реального времени без выполнения блокирующего системного вызова. Для работы ограничения, всякий раз когда процесс делает блокирующий системный вызов счётчик использованного времени ЦП сбрасывается в ноль. Счётчик времени ЦП не сбрасывается, если процесс продолжает пытаться использовать ЦП, но был вытеснен, его выделенное время на исполнение истекло или он вызвал sched_yield(2).

При достижении мягкого ограничения процессу посылается сигнал SIGXCPU. Если процесс перехватил сигнал, проигнорировал его и продолжает потреблять время ЦП, то раз в секунду будет генерироваться сигнал SIGXCPU до тех пор, пока не будет достигнуто жёсткое ограничение, и процессу не будет послан сигнал SIGKILL.

Это ограничение предназначено для предотвращения блокировки системы вышедшими из под контроля процессами реального времени.

Определяет ограничение на количество сигналов, которые могут быть поставлены в очередь вызывающего процесса с реальным пользовательским идентификатором. При проверке ограничения учитываются обычные сигналы и сигналы реального времени. Однако ограничение учитывается только в sigqueue(3); всегда возможно использовать kill(2) для постановки в очередь любого сигнала, которого ещё нет в очереди процесса.
Максимальный размер стека процесса в байтах. При достижении этого ограничения генерируется сигнал SIGSEGV. Для обработки этого сигнала процесс должен использовать альтернативный стек сигналов (sigaltstack(2)).

Начиная с Linux 2.6.23, это ограничение также определяет количество места, используемого для аргументов командной строки процесса и его переменных окружения; подробней об этом смотрите в execve(2).

prlimit()

Системный вызов prlimit(), который есть только в Linux объединяет и расширяет функции setrlimit() и getrlimit(). Он может использоваться для задания и получения ограничений ресурсов произвольного процесса.

Аргумент resource имеет тот же смысл что и в setrlimit() и getrlimit().

Если значение аргумента new_limit не равно NULL, то структура rlimit, на которую он указывает, используется для задания новых значений мягкий и жёстких ограничений для resource. Если значение аргумента old_limit не равно NULL, то успешный вызов prlimit() помещает текущие значения мягких и жёстких ограничений для resource в структуру rlimit, на которую указывает old_limit.

В аргументе pid задаётся идентификатор процесса с которым работает вызыв. Если pid равно 0, то вызов применяется к вызывающему процессу. Для установки и получения ресурсов не своего процесса, вызывающий должен иметь мандат CAP_SYS_RESOURCE или реальный, эффективный и сохранённый идентификатор пользователя процесса назначения должен совпадать с реальным идентификатором пользователя вызывающего и реальный, эффективный и сохранённый идентификатор группы процесса назначения должны совпадать с реальным идентификатором группы вызывающего.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

Аргумент-указатель указывает за пределы доступного адресного пространства.
Указано некорректное значение resource; или для setrlimit() или prlimit(): rlim->rlim_cur больше чем rlim->rlim_max.
Непривилегированный процесс пытался увеличить жёсткое ограничение; для этого требуется мандат CAP_SYS_RESOURCE. Или вызывающий увеличить жёсткое ограничение RLIMIT_NOFILE, превышая текущий максимум ядра (NR_OPEN). Или вызывающий процесс не имеет прав для назначения ограничений процессу, указанному в pid.
Не удалось найти процесс с идентификатором, указанном в pid.

ВЕРСИИ

Системный вызов prlimit() появился в Linux 2.6.36. Поддержка в glibc доступна начиная с версии 2.13.

СООТВЕТСТВИЕ СТАНДАРТАМ

getrlimit(), setrlimit(): SVr4, 4.3BSD, POSIX.1-2001.
prlimit(): только в Linux.

Ограничение RLIMIT_MEMLOCK и RLIMIT_NPROC появились из BSD и их нет в POSIX.1-2001; они есть в BSD и Linux, но реализации несколько различны. Ограничение RLIMIT_RSS появилось из BSD и его нет в POSIX.1-2001; тем не менее оно есть в большинстве реализаций. Ограничения RLIMIT_MSGQUEUE, RLIMIT_NICE, RLIMIT_RTPRIO, RLIMIT_RTTIME и RLIMIT_SIGPENDING есть только в Linux.

ЗАМЕЧАНИЯ

Дочерний процесс, созданный fork(2), наследует ограничения ресурсов родителя. Ограничения ресурсов сохраняются при execve(2).

Ограничения ресурсов интерпретатора командной строки можно устанавливать с помощью встроенной команды ulimit (limit в csh(1)). Ограничения ресурсов интерпретатора наследуются дочерними процессами, которые он создаёт при выполнении команд.

В старых системах была функция vlimit() с подобным setrlimit() назначением. Для обратной совместимости в glibc также есть функция vlimit(). Во всех новых приложениях должен быть использован setrlimit().

ПРИМЕР

Представленная ниже программа показывает использование prlimit().

#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#define errExit(msg) 	do { perror(msg); exit(EXIT_FAILURE); \

} while (0) int main(int argc, char *argv[]) {
struct rlimit old, new;
struct rlimit *newp;
pid_t pid;
if (!(argc == 2 || argc == 4)) {
fprintf(stderr, "Использование: %s <pid> [<новое-мягкое-ограничение> "
"<новое-жёсткое-ограничение>]\n", argv[0]);
exit(EXIT_FAILURE);
}
pid = atoi(argv[1]); /* PID процесса назначения */
newp = NULL;
if (argc == 4) {
new.rlim_cur = atoi(argv[2]);
new.rlim_max = atoi(argv[3]);
newp = &new;
}
/* Установить ограничение на время ЦП процесса назначения;
получить и показать предыдущее ограничение */
if (prlimit(pid, RLIMIT_CPU, newp, &old) == -1)
errExit("prlimit-1");
printf("Previous limits: soft=%lld; hard=%lld\n",
(long long) old.rlim_cur, (long long) old.rlim_max);
/* Получить и показать новое ограничение времени ЦП */
if (prlimit(pid, RLIMIT_CPU, NULL, &old) == -1)
errExit("prlimit-2");
printf("Новые ограничения: мягкое=%lld; жёсткое=%lld\n",
(long long) old.rlim_cur, (long long) old.rlim_max);
exit(EXIT_FAILURE); }

ДЕФЕКТЫ

В старых ядрах Linux сигналы SIGXCPU и SIGKILL, посылаемые когда у процесса обнаруживается достижение мягкого и жёсткого ограничения RLIMIT_CPU, доставляются на одну секунду (ЦП) позднее чем это должно быть. Это исправлено в ядре версии 2.6.8.

В ядрах 2.6.x до версии 2.6.17, ограничение RLIMIT_CPU равное 0, неправильно воспринималось как «без ограничения» (подобно RLIM_INFINITY). Начиная с Linux 2.6.17, установка ограничения в 0 действует, но реально обрабатывается как ограничение в 1 секунду.

Из-за дефекта ядра RLIMIT_RTPRIO не работает в версии 2.6.12; это исправлено в ядре 2.6.13.

В ядре 2.6.12 было несоответствие в единицу между диапазонами приоритетов, возвращаемых getpriority(2) и RLIMIT_NICE. Это приводило к тому, что реальный максимум значения nice вычислялся как 19 -  rlim_cur. Исправлено в ядре 2.6.13.

В ядрах до 2.4.22 не определялась ошибка EINVAL в setrlimit(), если значение rlim->rlim_cur было больше rlim->rlim_max.

СМОТРИТЕ ТАКЖЕ

dup(2), fcntl(2), fork(2), getrusage(2), mlock(2), mmap(2), open(2), quotactl(2), sbrk(2), shmctl(2), malloc(3), sigqueue(3), ulimit(3), core(5), capabilities(7), signal(7)

2011-09-10 Linux